/*
 * @Author: sympsel sympsel@outlook.com
 * @Date: 2025-08-01 10:51:39
 * @LastEditors: sympsel sympsel@outlook.com
 * @LastEditTime: 2025-09-08 21:56:53
 * @FilePath: \work25_8_1\src\Date.cpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置:
 * https://github.co</OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

#include <iostream>

#include "Date.h"
#include "stdexcept"

int Date::GetMonthDay(int year, int month) {
    switch (month) {
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:
            return 31;
        case 4:
        case 6:
        case 9:
        case 11:
            return 30;
        case 2:
            if (IsLeapYear(year)) {
                return 29;
            }
            return 28;

        default:
            throw std::invalid_argument("Invalied Month!");
    }
}

int Date::GetYearDay(int year) { return IsLeapYear(year) ? 366 : 365; }

bool Date::IsLeapYear(int year) { return year % 400 == 0 || year % 4 == 0 && year % 100 != 0; }

bool Date::Check(int year, int month, int day) {
    return !(year <= 0 || day > GetMonthDay(year, month) || day < 1 || month > 12 || month < 1);
}

void Date::PrintWithWeekday(int year, int month, int day) {
    Date d1(2025, 8, 3);
    Date d2(year, month, day);
    int day_diff = d2 - d1;
    switch ((day_diff % 7 + 7) % 7) {
        case 1:
            std::cout << "Monday";
            break;
        case 2:
            std::cout << "Tuesday";
            break;
        case 3:
            std::cout << "Wednesday";
            break;
        case 4:
            std::cout << "Thursday";
            break;
        case 5:
            std::cout << "Friday";
            break;
        case 6:
            std::cout << "Saturday";
            break;
        case 0:
            std::cout << "Sunday";
            break;
    }
    std::cout << " " << year << "-" << month << "-" << day << std::endl;
}

Date::Date(int year, int month, int day) {
    if (!Check(year, month, day)) {
        throw std::invalid_argument("Invalied Argument");
    }
    _year = year;
    _month = month;
    _day = day;
}
Date::Date(const Date& d) {
    if (this != &d) {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
}
Date& Date::operator=(const Date& d) {
    if (this != &d) {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
    return *this;
}
Date::~Date() {}

Date Date::operator+(int day) {
    Date temp(*this);
    temp += day;
    return temp;
}
Date Date::operator-(int day) {
    Date temp(*this);
    temp -= day;
    return temp;
}

Date& Date::operator+=(int day) {
    if (day < 0) {
        return *this -= -day;
    }
    day += _day;
    while (day > GetMonthDay(_year, _month)) {
        day -= GetMonthDay(_year, _month);
        ++_month;
        if (_month > 12) {
            ++_year;
            _month -= 12;
        }
    }
    _day = day;
    return *this;
}

Date& Date::operator-=(int day) {
    if (day < 0) {
        return *this += -day;
    }
    while (true) {
        if (_day > day) {
            _day -= day;
            return *this;
        }
        --_month;
        if (_month < 1) {
            --_year;
            _month = 12;
        }
        if (_day == day) {
            _day = GetMonthDay(_year, _month);
            return *this;
        }
        day -= GetMonthDay(_year, _month);
    }
}

Date& Date::operator++() {
    ++_day;
    if (_day > GetMonthDay(_year, _month)) {
        _day -= GetMonthDay(_year, _month);
        ++_month;
        if (_month > 12) {
            ++_year;
            _month -= 12;
        }
    }
    return *this;
}

Date Date::operator++(int) {
    Date temp(*this);
    ++(*this);
    return temp;
}
Date& Date::operator--() {
    if (_day == 1 && _month == 1) {
        --_year;
        _day = 31;
        _month = 12;
    } else if (_day == 1) {
        --_month;
        _day = GetMonthDay(_year, _month);
    } else {
        --_day;
    }
    return *this;
}
Date Date::operator--(int) {
    Date temp(*this);
    --(*this);
    return temp;
}
bool Date::operator>(const Date& d) {
    if (_year > d._year) {
        return true;
    } else if (_year < d._year) {
        return false;
    } else {
        if (_month > d._month) {
            return true;
        } else if (_month < d._month) {
            return false;
        } else {
            if (_day > d._day) {
                return true;
            }
            return false;
        }
    }
}
bool Date::operator==(const Date& d) {
    return _day == d._day && _month == d._month && _year == d._year;
}
bool Date::operator>=(const Date& d) { return *this == d || *this > d; }
bool Date::operator<(const Date& d) { return !(*this >= d); }
bool Date::operator<=(const Date& d) { return !(*this > d); }
bool Date::operator!=(const Date& d) {
    return _day != d._day || _month != d._month || _year != d._year;
}
int Date::operator-(const Date& d) {
    if (*this == d) {
        return 0;
    }
    Date start = *this > d ? d : *this;
    Date end = *this > d ? *this : d;

    int day = 0;
    // while (end != start) {
    //     ++start;
    //     ++day;
    // }

    for (int year = start._year; year < end._year; ++year) {
        day += GetYearDay(year);
    }

    for (int month = 1; month < start._month; ++month) {
        day -= GetMonthDay(start._year, month);
    }
    day -= start._day;

    for (int month = 1; month < end._month; ++month) {
        day += GetMonthDay(end._year, month);
    }
    day += end._day;

    return *this > d ? day : -day;
}

// void Date::operator<<(ostream& out) {
//     out << _year << "-" << _month << "-" << _day << std::endl;
// }

ostream& operator<<(ostream& out, const Date& d) {
    out << d._year << "-" << d._month << "-" << d._day;
    return out;
}

istream& operator>>(istream& in, Date& d) {
    std::cout << "input \"year month day\", split with Space: ";
    
    int year, month, day;
    in >> year >> month >> day;
    
    // 验证输入的有效性
    if (in.fail()) {
        in.setstate(ios::failbit);
        return in;
    }
    
    // 验证日期是否有效
    if (!Date::Check(year, month, day)) {
        in.setstate(ios::failbit);
        std::cout << "Invalid date!" << std::endl;
        return in;
    }
    
    // 设置日期
    d._year = year;
    d._month = month;
    d._day = day;
    
    return in;
}

void Date::Print() { std::cout << _year << "-" << _month << "-" << _day << std::endl; }
